#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <Preferences.h>
#include <PubSubClient.h>

ESP8266WebServer server(80);
Preferences preferences;
WiFiClient espClient;
PubSubClient client(espClient);

// ===== 配置参数 =========================
String wifi_ssid = "";
String wifi_password = "";
String mqtt_server = "broker.emqx.io"; // 默认MQTT服务器
int mqtt_port = 1883;
String mqtt_user = "";
String mqtt_pw = "";
String topic = "led";
String static_ip = "";
String ap_ip = "192.168.4.1"; // AP模式默认IP
bool ap_mode = false;

// ===== GPIO控制 =========================
const int control_gpio = 3;  // GPIO3 (FLASH按钮)
const int ledPin = 2;        // 作为状态指示灯 (GPIO2)
bool gpio_state = false;

// ===== AP模式配置 =========================
const char* ap_ssid = "QingHe-Zongyuxian";
const char* ap_password = "12345678";

// ===== 状态变量 =========================
unsigned long previousMillis = 0;
const long interval = 10000; // WiFi重连间隔
int wifi_reconnect_attempts = 0;
const int max_reconnect_attempts = 5; // 最大重试次数
unsigned long lastMqttReconnectAttempt = 0;
const long mqttReconnectInterval = 5000; // MQTT重连间隔

// ===== 网页界面 =========================
const char* setupPage = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ESP网页配置</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f0f0f0;
            margin: 0;
            padding: 20px;
        }
        .container {
            max-width: 500px;
            margin: 0 auto;
            background-color: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
        }
        h1 {
            text-align: center;
            color: #333;
        }
        .form-group {
            margin-bottom: 15px;
        }
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        input[type="text"],
        input[type="password"],
        input[type="number"] {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            box-sizing: border-box;
        }
        button {
            background-color: #4CAF50;
            color: white;
            padding: 12px 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            width: 100%;
            font-size: 16px;
            margin-top: 10px;
        }
        button:hover {
            background-color: #45a049;
        }
        .switch {
            position: relative;
            display: inline-block;
            width: 60px;
            height: 34px;
        }
        .switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }
        .slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            transition: .4s;
            border-radius: 34px;
        }
        .slider:before {
            position: absolute;
            content: "";
            height: 26px;
            width: 26px;
            left: 4px;
            bottom: 4px;
            background-color: white;
            transition: .4s;
            border-radius: 50%;
        }
        input:checked + .slider {
            background-color: #2196F3;
        }
        input:checked + .slider:before {
            transform: translateX(26px);
        }
        .status {
            padding: 10px;
            margin-top: 15px;
            border-radius: 5px;
            text-align: center;
        }
        .connected {
            background-color: #d4edda;
            color: #155724;
        }
        .disconnected {
            background-color: #f8d7da;
            color: #721c24;
        }
        .info-box {
            background-color: #e9ecef;
            padding: 15px;
            border-radius: 5px;
            margin-bottom: 15px;
        }
        .info-box h3 {
            margin-top: 0;
            color: #495057;
        }
        .info-item {
            margin-bottom: 5px;
            display: flex;
        }
        .info-label {
            font-weight: bold;
            min-width: 120px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>ESP01S配置</h1>
        
        <div class="info-box">
            <h3>设备信息</h3>
            <div class="info-item"><span class="info-label">设备IP:</span> <span id="device-ip">%DEVICE_IP%</span></div>
            <div class="info-item"><span class="info-label">运行模式:</span> <span id="device-mode">%DEVICE_MODE%</span></div>
            <div class="info-item"><span class="info-label">芯片ID:</span> %CHIP_ID%</div>
            <div class="info-item"><span class="info-label">固件版本:</span> 1.0</div>
        </div>
        
        <div id="wifi-status" class="status %WIFI_STATUS_CLASS%">%WIFI_STATUS_MSG%</div>
        <div id="mqtt-status" class="status %MQTT_STATUS_CLASS%">%MQTT_STATUS_MSG%</div>
        
        <div class="info-box">
            <h3>当前配置</h3>
            <div class="info-item"><span class="info-label">WiFi名称:</span> %SSID%</div>
            <div class="info-item"><span class="info-label">WiFi密码:</span> ********</div>
            <div class="info-item"><span class="info-label">静态IP:</span> %STATIC_IP%</div>
            <div class="info-item"><span class="info-label">MQTT服务器:</span> %MQTT_SERVER%</div>
            <div class="info-item"><span class="info-label">MQTT端口:</span> %MQTT_PORT%</div>
            <div class="info-item"><span class="info-label">MQTT用户:</span> %MQTT_USER%</div>
            <div class="info-item"><span class="info-label">MQTT密码:</span> ********</div>
            <div class="info-item"><span class="info-label">MQTT主题:</span> %TOPIC%</div>
        </div>
        
        <form action="/saveconfig" method="post">
            <div class="form-group">
                <label for="ssid">WiFi SSID:</label>
                <input type="text" id="ssid" name="ssid" value="%SSID%" required>
            </div>
            <div class="form-group">
                <label for="password">WiFi 密码:</label>
                <input type="password" id="password" name="password" value="%PASSWORD%" required>
            </div>
            <div class="form-group">
                <label for="static_ip">静态IP (可选):</label>
                <input type="text" id="static_ip" name="static_ip" value="%STATIC_IP%" placeholder="例如: 192.168.1.100">
            </div>
            <div class="form-group">
                <label for="mqtt_server">MQTT服务器:</label>
                <input type="text" id="mqtt_server" name="mqtt_server" value="%MQTT_SERVER%" required>
            </div>
            <div class="form-group">
                <label for="mqtt_port">MQTT端口:</label>
                <input type="number" id="mqtt_port" name="mqtt_port" value="%MQTT_PORT%">
            </div>
            <div class="form-group">
                <label for="mqtt_user">MQTT用户名:</label>
                <input type="text" id="mqtt_user" name="mqtt_user" value="%MQTT_USER%">
            </div>
            <div class="form-group">
                <label for="mqtt_pw">MQTT密码:</label>
                <input type="password" id="mqtt_pw" name="mqtt_pw" value="%MQTT_PW%">
            </div>
            <div class="form-group">
                <label for="topic">MQTT主题:</label>
                <input type="text" id="topic" name="topic" value="%TOPIC%" required>
            </div>
            <button type="submit">保存配置并重启</button>
        </form>
        
        <div class="form-group">
            <label>灯光控制:</label>
            <label class="switch">
                <input type="checkbox" id="gpioToggle" onchange="controlGPIO()">
                <span class="slider"></span>
            </label>
        </div>
        
        <button onclick="restartDevice()">重启设备</button>
        <button onclick="resetConfig()" style="background-color: #dc3545;">恢复出厂设置</button>
    </div>
    
    <script>
        function controlGPIO() {
            var xhr = new XMLHttpRequest();
            var state = document.getElementById("gpioToggle").checked;
            xhr.open("GET", "/control?gpio0=" + (state ? "on" : "off"), true);
            xhr.send();
        }
        
        function restartDevice() {
            if(confirm("确定要重启设备吗？")) {
                fetch('/restart')
                    .then(response => {
                        alert("设备正在重启，请稍后刷新页面");
                    });
            }
        }
        
        function resetConfig() {
            if(confirm("确定要恢复出厂设置吗？所有配置将被清除，设备将进入配网模式！")) {
                fetch('/reset')
                    .then(response => {
                        alert("配置已清除，设备正在重启并进入配网模式");
                    });
            }
        }
        
        // 初始化页面时获取GPIO状态
        window.onload = function() {
            fetch('/status')
                .then(response => response.json())
                .then(data => {
                    document.getElementById("gpioToggle").checked = data.gpio0;
                });
                
            // 更新设备IP和模式
            fetch('/deviceinfo')
                .then(response => response.json())
                .then(data => {
                    document.getElementById("device-ip").textContent = data.ip;
                    document.getElementById("device-mode").textContent = data.mode;
                });
        }
        
        // 每10秒更新一次状态
        setInterval(function() {
            fetch('/status')
                .then(response => response.json())
                .then(data => {
                    document.getElementById("gpioToggle").checked = data.gpio0;
                });
                
            fetch('/deviceinfo')
                .then(response => response.json())
                .then(data => {
                    document.getElementById("device-ip").textContent = data.ip;
                    document.getElementById("device-mode").textContent = data.mode;
                });
                
            fetch('/connectionstatus')
                .then(response => response.json())
                .then(data => {
                    document.getElementById("wifi-status").textContent = data.wifi;
                    document.getElementById("wifi-status").className = "status " + (data.wifi.includes("已连接") ? "connected" : "disconnected");
                    
                    document.getElementById("mqtt-status").textContent = data.mqtt;
                    document.getElementById("mqtt-status").className = "status " + (data.mqtt.includes("已连接") ? "connected" : "disconnected");
                });
        }, 10000);
    </script>
</body>
</html>
)rawliteral";

// ===== 初始化配置 =========================
void loadConfig() {
    preferences.begin("esp01", true);
    wifi_ssid = preferences.getString("ssid", "");
    wifi_password = preferences.getString("password", "");
    static_ip = preferences.getString("static_ip", "");
    mqtt_server = preferences.getString("mqtt_server", "broker.emqx.io");
    mqtt_port = preferences.getUShort("mqtt_port", 1883);
    mqtt_user = preferences.getString("mqtt_user", "");
    mqtt_pw = preferences.getString("mqtt_pw", "");
    topic = preferences.getString("topic", "led");
    preferences.end();
}

// ===== 保存配置 =========================
void saveConfig() {
    preferences.begin("esp01", false);
    preferences.putString("ssid", wifi_ssid);
    preferences.putString("password", wifi_password);
    preferences.putString("static_ip", static_ip);
    preferences.putString("mqtt_server", mqtt_server);
    preferences.putUShort("mqtt_port", mqtt_port);
    preferences.putString("mqtt_user", mqtt_user);
    preferences.putString("mqtt_pw", mqtt_pw);
    preferences.putString("topic", topic);
    preferences.end();
}

// ===== AP模式设置 =========================
void startAPMode() {
    ap_mode = true;
    WiFi.mode(WIFI_AP);
    WiFi.softAPConfig(IPAddress(192,168,4,1), IPAddress(192,168,4,1), IPAddress(255,255,255,0));
    WiFi.softAP(ap_ssid, ap_password);
    
    // 设置AP模式下的服务器路由
    server.on("/", handleRoot);
    server.on("/saveconfig", HTTP_POST, handleSaveConfig);
    server.on("/control", handleControlGPIO);
    server.on("/status", handleStatus);
    server.on("/deviceinfo", handleDeviceInfo);
    server.on("/connectionstatus", handleConnectionStatus);
    server.on("/restart", handleRestart);
    server.on("/reset", handleReset);
    server.begin();
    Serial.println("AP模式已启动");
    // 指示灯慢闪表示AP模式
    digitalWrite(ledPin, LOW);
}

// ===== STA模式设置 =========================
void startSTAMode() {
    ap_mode = false;
    WiFi.disconnect(true);  // 确保之前连接已断开
    // 设置STA模式下的服务器路由
    server.on("/", handleRoot);
    server.on("/saveconfig", HTTP_POST, handleSaveConfig);
    server.on("/control", handleControlGPIO);
    server.on("/status", handleStatus);
    server.on("/deviceinfo", handleDeviceInfo);
    server.on("/connectionstatus", handleConnectionStatus);
    server.on("/restart", handleRestart);
    server.on("/reset", handleReset);
    server.begin();
    Serial.println(WiFi.localIP());
    // 指示灯快闪表示STA模式
    digitalWrite(ledPin, HIGH);
}

// ===== 处理根请求 =========================
void handleRoot() {
    String page = setupPage;
    page.replace("%SSID%", wifi_ssid);
    page.replace("%PASSWORD%", wifi_password);
    page.replace("%STATIC_IP%", static_ip);
    page.replace("%MQTT_SERVER%", mqtt_server);
    page.replace("%MQTT_PORT%", String(mqtt_port));
    page.replace("%MQTT_USER%", mqtt_user);
    page.replace("%MQTT_PW%", mqtt_pw);
    page.replace("%TOPIC%", topic);
    page.replace("%CHIP_ID%", String(ESP.getChipId()));
    
    // 添加设备IP和模式信息
    String deviceIp = ap_mode ? WiFi.softAPIP().toString() : WiFi.localIP().toString();
    String deviceMode = ap_mode ? "AP模式 (配网)" : "STA模式 (已连接)";
    page.replace("%DEVICE_IP%", deviceIp);
    page.replace("%DEVICE_MODE%", deviceMode);
    
    // 添加WiFi状态信息
    if (WiFi.status() == WL_CONNECTED) {
        page.replace("%WIFI_STATUS_CLASS%", "connected");
        page.replace("%WIFI_STATUS_MSG%", "WiFi已连接: " + wifi_ssid + " | IP: " + WiFi.localIP().toString());
    } else {
        page.replace("%WIFI_STATUS_CLASS%", "disconnected");
        page.replace("%WIFI_STATUS_MSG%", "WiFi未连接，当前为AP模式");
    }
    
    // 添加MQTT状态信息
    if (client.connected()) {
        page.replace("%MQTT_STATUS_CLASS%", "connected");
        page.replace("%MQTT_STATUS_MSG%", "MQTT已连接: " + mqtt_server);
    } else {
        page.replace("%MQTT_STATUS_CLASS%", "disconnected");
        page.replace("%MQTT_STATUS_MSG%", "MQTT未连接");
    }
    
    server.send(200, "text/html", page);
}

// ===== 处理保存配置请求 =========================
void handleSaveConfig() {
    wifi_ssid = server.arg("ssid");
    wifi_password = server.arg("password");
    static_ip = server.arg("static_ip");
    mqtt_server = server.arg("mqtt_server");
    mqtt_port = server.arg("mqtt_port").toInt();
    mqtt_user = server.arg("mqtt_user");
    mqtt_pw = server.arg("mqtt_pw");
    topic = server.arg("topic");
    
    saveConfig();
    
    String message = "<html><body><h1>配置已保存，设备将重启</h1><p>请等待设备重新连接...</p></body></html>";
    server.send(200, "text/html", message);
    
    delay(1000);
    ESP.restart();
}

// ===== 处理GPIO控制请求 =========================
void handleControlGPIO() {
  if (server.hasArg("gpio0")) {
    String state = server.arg("gpio0");
    if (state == "on") {
      digitalWrite(0, LOW); // 假设GPIO0控制继电器
      gpio_state = true;
    } else if (state == "off") {
      digitalWrite(0, HIGH);
      gpio_state = false;
    }
    server.send(200, "text/plain", "OK");
  } else {
    server.send(400, "text/plain", "Bad Request");
  }
}

// ===== 处理状态查询请求 =========================
void handleStatus() {
    String json = "{\"gpio0\":" + String(gpio_state ? "true" : "false") + "}";
    server.send(200, "application/json", json);
}

// ===== 处理设备信息请求 =========================
void handleDeviceInfo() {
    String ip = ap_mode ? WiFi.softAPIP().toString() : WiFi.localIP().toString();
    String mode = ap_mode ? "AP模式" : "STA模式";
    String json = "{\"ip\":\"" + ip + "\", \"mode\":\"" + mode + "\"}";
    server.send(200, "application/json", json);
}

// ===== 处理连接状态请求 =========================
void handleConnectionStatus() {
    String wifiStatus = WiFi.status() == WL_CONNECTED ? 
        "WiFi已连接: " + wifi_ssid + " | IP: " + WiFi.localIP().toString() : 
        "WiFi未连接";
    
    String mqttStatus = client.connected() ? 
        "MQTT已连接: " + mqtt_server : 
        "MQTT未连接: " + String(client.state());
    
    String json = "{\"wifi\":\"" + wifiStatus + "\", \"mqtt\":\"" + mqttStatus + "\"}";
    server.send(200, "application/json", json);
}

// ===== 处理重启请求 =========================
void handleRestart() {
    server.send(200, "text/plain", "正在重启...");
    delay(1000);
    ESP.restart();
}

// ===== 处理重置请求 =========================
void handleReset() {
    preferences.begin("esp01", false);
    preferences.clear();
    preferences.end();
    
    server.send(200, "text/plain", "配置已清除，正在重启进入配网模式...");
    delay(5000);
    ESP.restart();
}

// ===== 连接WiFi =========================
bool connectToWiFi() {
    if (wifi_ssid == "") {
        Serial.println("未配置WiFi，启动AP模式");
        return false;
    }

    Serial.println("正在连接WiFi: " + wifi_ssid);
    WiFi.mode(WIFI_STA);
    
    // 配置静态IP（如果设置了）
    if (static_ip != "") {
        IPAddress ip, gateway, subnet;
        if (ip.fromString(static_ip)) {
            // 假设网关是IP的最后一位为1
            String gatewayStr = static_ip.substring(0, static_ip.lastIndexOf('.')) + ".1";
            if (!gateway.fromString(gatewayStr)) {
                gateway.fromString("192.168.1.1"); // 默认网关
            }
            subnet.fromString("255.255.255.0");
            WiFi.config(ip, gateway, subnet);
            Serial.println("使用静态IP: " + static_ip);
        }
    }

    WiFi.begin(wifi_ssid.c_str(), wifi_password.c_str());
    
    int attempts = 0;
    const int maxAttempts = 20; // 尝试20次，每次500ms，总共10秒
    
    while (WiFi.status() != WL_CONNECTED && attempts < maxAttempts) {
        delay(500);
        Serial.print(".");
        // 指示灯闪烁表示正在连接
        digitalWrite(ledPin, !digitalRead(ledPin));
        attempts++;
    }
    
    if (WiFi.status() == WL_CONNECTED) {
        Serial.println(WiFi.localIP());
        digitalWrite(ledPin, HIGH); // 常亮表示连接成功
        wifi_reconnect_attempts = 0; // 重置重连尝试次数
        return true;
    } else {
        Serial.println("\nWiFi连接失败");
        digitalWrite(ledPin, LOW); // 熄灭表示连接失败
        return false;
    }
}

// ===== MQTT回调函数 =========================
void mqttCallback(char* topicChar, byte* payload, unsigned int length) {
    Serial.print("MQTT消息到达 [");
    Serial.print(topicChar);
    Serial.print("] ");
    
    String message = "";
    for (int i = 0; i < length; i++) {
        message += (char)payload[i];
    }
    Serial.println(message);

    // 比较主题，使用全局变量topic
    if (String(topicChar) == topic) {
        if (message == "0" || message == "off" || message == "false") {
            digitalWrite(control_gpio, LOW);
            gpio_state = false;

        } else if (message == "1" || message == "on" || message == "true") {
            digitalWrite(control_gpio, HIGH);
            gpio_state = true;

        }
    }
}

// ===== MQTT连接函数 =========================
bool connectMQTT() {
    if (mqtt_server == "") {
        Serial.println("未配置MQTT服务器");
        return false;
    }
    
    client.setServer(mqtt_server.c_str(), mqtt_port);
    client.setCallback(mqttCallback);
    
    Serial.println("正在连接MQTT服务器: " + mqtt_server);
    
    String clientId = "ESP01Client-" + String(ESP.getChipId());
    
    if (mqtt_user != "" && mqtt_pw != "") {
        // 使用用户名和密码连接
        if (client.connect(clientId.c_str(), mqtt_user.c_str(), mqtt_pw.c_str())) {
            client.subscribe(topic.c_str());
            Serial.println("=========MQTT配置=========");
            Serial.print("服务器: "); Serial.println(mqtt_server);
            Serial.print("端口: "); Serial.println(mqtt_port);
            Serial.print("主题: "); Serial.println(topic);
            Serial.println("=========================");
            
            // 发布当前状态
            client.publish(topic.c_str(), gpio_state ? "on" : "off");
            
            return true;
        }
    } else {
        // 不使用用户名和密码连接
        if (client.connect(clientId.c_str())) {
            client.subscribe(topic.c_str());
            Serial.println("MQTT连接成功");
            Serial.println("=========MQTT配置=========");
            Serial.print("服务器: "); Serial.println(mqtt_server);
            Serial.print("端口: "); Serial.println(mqtt_port);
            Serial.print("主题: "); Serial.println(topic);
            Serial.println("=========================");
            
            // 发布当前状态
            client.publish(topic.c_str(), gpio_state ? "on" : "off");
            
            return true;
        }
    }
    
    Serial.println("MQTT连接失败，错误代码: " + String(client.state()));
    return false;
}

// ===== SETUP函数 =========================
void setup() {
    Serial.begin(115200);
    Serial.println("\n启动ESP01设备...");
    
    // 初始化GPIO
    pinMode(control_gpio, OUTPUT);
    digitalWrite(control_gpio, LOW);
    pinMode(ledPin, OUTPUT);
    digitalWrite(ledPin, LOW); // 初始关闭指示灯
    
    // 加载配置
    loadConfig();
    
    // 尝试连接WiFi
    if (connectToWiFi()) {
        // WiFi连接成功，启动STA模式
        startSTAMode();
        
        // 尝试连接MQTT
        if (connectMQTT()) {
            Serial.println("系统启动完成，WiFi和MQTT均已连接");
        } else {
            Serial.println("系统启动完成，WiFi已连接但MQTT连接失败");
        }
    } else {
        // WiFi连接失败，启动AP模式
        Serial.println("WiFi连接失败，启动AP模式进行配置");
        startAPMode();
    }
}

// ===== LOOP函数 =========================
void loop() {
    server.handleClient();
    
    // 处理WiFi连接状态
    if (!ap_mode && WiFi.status() != WL_CONNECTED) {
        unsigned long currentMillis = millis();
        if (currentMillis - previousMillis >= interval) {
            previousMillis = currentMillis;
            
            digitalWrite(ledPin, LOW); // 指示灯熄灭表示断开
            
            if (wifi_reconnect_attempts < max_reconnect_attempts) {
                wifi_reconnect_attempts++;
                
                if (connectToWiFi()) {
                    // 尝试重新连接MQTT
                    if (!client.connected()) {
                        connectMQTT();
                    }
                }
            } else {
                // 超过最大重试次数，切换到AP模式
                startAPMode();
            }
        }
    }
    
    // 处理MQTT通信
    if (!ap_mode && WiFi.status() == WL_CONNECTED) {
        if (!client.connected()) {
            // MQTT断开连接，尝试重连
            if (millis() - lastMqttReconnectAttempt > mqttReconnectInterval) {
                lastMqttReconnectAttempt = millis();
                if (connectMQTT()) {

                }
            }
        } else {
            client.loop();
        }
    }
    
    // 在AP模式下闪烁指示灯
    if (ap_mode) {
        static unsigned long lastBlink = 0;
        if (millis() - lastBlink > 1000) {
            lastBlink = millis();
            digitalWrite(ledPin, !digitalRead(ledPin));
        }
    }
    
    delay(10);
}